package io.coderyeah.ymcc.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import io.coderyeah.ymcc.constant.RedisConstants;
import io.coderyeah.ymcc.constant.YmccConstants;
import io.coderyeah.ymcc.domain.Course;
import io.coderyeah.ymcc.domain.CourseOrder;
import io.coderyeah.ymcc.domain.CourseOrderItem;
import io.coderyeah.ymcc.dto.KillOrderParamDto;
import io.coderyeah.ymcc.dto.OrderParamDTO;
import io.coderyeah.ymcc.dto.PayMsgInMQ;
import io.coderyeah.ymcc.dto.PreOrderDTO;
import io.coderyeah.ymcc.enums.YmccSystemError;
import io.coderyeah.ymcc.feign.client.CourseServiceClient;
import io.coderyeah.ymcc.mapper.CourseOrderMapper;
import io.coderyeah.ymcc.result.JSONResult;
import io.coderyeah.ymcc.service.ICourseOrderItemService;
import io.coderyeah.ymcc.service.ICourseOrderService;
import io.coderyeah.ymcc.util.AssertUtil;
import io.coderyeah.ymcc.util.CodeGenerateUtils;
import io.coderyeah.ymcc.vo.CourseInfoVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.client.producer.SendStatus;
import org.apache.rocketmq.client.producer.TransactionSendResult;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.redisson.api.RSemaphore;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author coderyeah
 * @since 2022-11-02
 */
@Service
@Slf4j
public class CourseOrderServiceImpl extends ServiceImpl<CourseOrderMapper, CourseOrder> implements ICourseOrderService {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private CourseServiceClient courseServiceClient;
    @Autowired
    private ICourseOrderItemService itemService;
    @Autowired
    private RocketMQTemplate mqTemplate;
    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;
    @Autowired
    private RedissonClient redissonClient;


    @Override
    public String placeOrder(OrderParamDTO dto) {
        List<Long> courseIds = dto.getCourseIds();
        AssertUtil.isNotNull(courseIds, YmccSystemError.INVALID_REQUEST_PARAMETER.getMessage());
        // 将courseIds转换成字符串用来作为key查询redis数据
        String ids = StringUtils.join(courseIds, ",");
        // 获取登录用户 fixme
        long loginId = 3L;
        String val = stringRedisTemplate.opsForValue().get(RedisConstants.ORDER_TOKEN + loginId + ":" + ids);
        // 如果redis的token为空就表明订单已经被创建
        AssertUtil.isNotNull(val, YmccSystemError.ORDER_EXISTED.getMessage());
        // 判断token是否相等 防止重复下单
        AssertUtil.isEqualsTrim(dto.getToken(), val, YmccSystemError.ORDER_EXISTED.getMessage());

        // 调用远程服务获取课程详细信息
        JSONResult jsonResult = courseServiceClient.getCourseInfo(courseIds);
        String jsonString = JSON.toJSONString(jsonResult.getData());
        CourseInfoVo courseInfoVo = JSON.parseObject(jsonString, CourseInfoVo.class);
        // 所有下单课程
        List<Course> courses = courseInfoVo.getCourses();
        // 通过用户id生成订单编号
        String orderSn = CodeGenerateUtils.generateOrderSn(loginId);

        // 构建订单对象下单
        CourseOrder order = placeOrder(0, loginId, courseInfoVo, orderSn);


//        insert(courseOrder);

        // 构建订单详情
        courses.forEach(course -> {
            CourseOrderItem item = createItem(orderSn, course);
            order.getItems().add(item);
//            itemService.insert(item);
        });

        // 封装发送到mq的消息
        PayMsgInMQ msgInMQ = new PayMsgInMQ();
        msgInMQ.setOrderNo(orderSn);
        msgInMQ.setPayType(order.getPayType());// 支付宝
        msgInMQ.setAmount(order.getPayAmount());
        msgInMQ.setUserId(loginId);
        msgInMQ.setSubject(order.getTitle());

        Map<String, Object> map = new HashMap<>();
        map.put("userId", loginId);
        map.put("courseIds", ids);
        msgInMQ.setExtParams(JSON.toJSONString(map));
        // MQ发送事务消息
        Message<PayMsgInMQ> message = MessageBuilder.withPayload(msgInMQ).build();
        // order是额外参数
        TransactionSendResult result = mqTemplate.sendMessageInTransaction("tx-order-producer", "order-topic:order-tags", message, order);
        SendStatus sendStatus = result.getSendStatus();
        AssertUtil.isTrue(sendStatus.equals(SendStatus.SEND_OK), "支付订单创建失败");


        //添加定时任务【延时消息实现】
        Message<String> msg = MessageBuilder.withPayload(orderSn).build();
        SendResult res = mqTemplate.syncSend("order-cancel-topic:order-cancel-tags", msg, 3000, 4);//30s
        if (!res.getSendStatus().equals(SendStatus.SEND_OK)) {
            //
            log.info("消息投递失败：{}", res);
        }

        // 删除redis token
        stringRedisTemplate.delete(RedisConstants.ORDER_TOKEN + loginId + ":" + ids);
        return orderSn;
    }

    private CourseOrderItem createItem(String orderSn, Course course) {
        CourseOrderItem item = new CourseOrderItem();
        item.setCourseId(course.getId());
        item.setOrderNo(orderSn);
        item.setCreateTime(new Date());
        item.setCourseName(course.getName());
        item.setCount(1);
        item.setVersion(0);
        item.setAmount(course.getCourseMarket().getPrice());
        item.setCoursePic(course.getPic());
        item.setSubtotalAmount(course.getCourseMarket().getPrice());
        item.setKillCourseId(0L);
        return item;
    }

    private CourseOrderItem createKillItem(PreOrderDTO preOrderDto, Course course) {
        CourseOrderItem item = new CourseOrderItem();
        item.setCourseId(course.getId());
        item.setOrderNo(preOrderDto.getOrderNo());
        item.setCreateTime(new Date());
        item.setCourseName(course.getName());
        item.setCount(1);
        item.setVersion(0);
        item.setAmount(preOrderDto.getKillPrice());
        item.setCoursePic(course.getPic());
        item.setSubtotalAmount(preOrderDto.getKillPrice());
        item.setKillCourseId(preOrderDto.getKillId());
        return item;
    }


    private CourseOrder placeOrder(Integer type, long loginId, CourseInfoVo courseInfoVo, String orderSn) {
        CourseOrder courseOrder = new CourseOrder();
        courseOrder.setOrderNo(orderSn);
        courseOrder.setOrderType(type);// 0 普通订单
        courseOrder.setCreateTime(new Date());
        // 支付方式:0余额直接，1支付宝，2微信,3银联
        courseOrder.setPayType(1);// 支付宝
        courseOrder.setTitle(YmccConstants.PURCHASE_COURSE_ORDER);
        courseOrder.setStatusOrder(CourseOrder.TO_BE_PAID);//订单状态 0待支付
        courseOrder.setUserId(loginId);
        courseOrder.setDiscountAmount(new BigDecimal("0.00"));
        // 秒杀数量
        courseOrder.setTotalCount(1);
        courseOrder.setTotalAmount(courseInfoVo.getTotalAmount());
        courseOrder.setPayAmount(courseOrder.getTotalAmount().subtract(courseOrder.getDiscountAmount()));
        courseOrder.setVersion(0);
        return courseOrder;
    }

    @Override
    public CourseOrder getByOrderNo(String orderNo) {
        Wrapper<CourseOrder> wrapper = new EntityWrapper<>();
        wrapper.eq("order_no", orderNo);
        return selectOne(wrapper);

    }

    @Transactional
    @Override
    public void saveCourseOrderAndItem(CourseOrder order) {
        // 保存订单
        insert(order);
        List<CourseOrderItem> items = order.getItems();
        // 保存订单明细
        items.forEach(item -> {
            item.setOrderId(order.getId());
            itemService.insert(item);
        });
    }


    @Override
    public void cancelOrder(String orderSn) {
        Long loginId = 3L;
        //根据订单查询订单
        CourseOrder courseOrder = getByOrderNo(orderSn);
        //判断订单是否需要取消
        if (courseOrder != null && courseOrder.getStatusOrder() == 0) {
            //超时取消订单
            courseOrder.setStatusOrder(4);
            courseOrder.setUpdateTime(new Date());
            updateById(courseOrder);

            // 通过订单号找出秒杀id
            Wrapper<CourseOrderItem> wrapper = new EntityWrapper<>();
            wrapper.eq("order_no", orderSn);
            CourseOrderItem item = itemService.selectOne(wrapper);
            // 删除redis中的订单数据
            Boolean delete = redisTemplate.delete(orderSn);
            Boolean aBoolean = redisTemplate.delete(loginId + ":" + item.getKillCourseId());
            log.info("超时redis数据删除成功~~~~~~~~~~");
            // 信号量加1
            RSemaphore semaphore = redissonClient.getSemaphore(item.getKillCourseId().toString());
            //                semaphore.acquire(1);
            semaphore.release(1);
        }
    }

    @Override
    public String killPlaceOrder(KillOrderParamDto killOrderParamDto) {
        // 获取登录用户 fixme
        long loginId = 3L;
        PreOrderDTO preOrderDto = (PreOrderDTO) redisTemplate.opsForValue().get(killOrderParamDto.getOrderNo());
        AssertUtil.isNotNull(preOrderDto, "请不要搞事情哦");
        String id = preOrderDto.getCourseId().toString();
        // token
        String val = stringRedisTemplate.opsForValue().get(RedisConstants.ORDER_TOKEN + preOrderDto.getLoginId() + ":" + id);

        // 如果redis的token为空就表明订单已经被创建
        AssertUtil.isNotNull(val, YmccSystemError.ORDER_EXISTED.getMessage());
        // 判断token是否相等 防止重复下单
        AssertUtil.isEqualsTrim(killOrderParamDto.getToken(), (String) val, YmccSystemError.ORDER_EXISTED.getMessage());

        // 调用远程服务获取课程详细信息
        List<Long> ids = new ArrayList<>();
        ids.add(Long.valueOf(id));
        JSONResult jsonResult = courseServiceClient.getCourseInfo(ids);
        String jsonString = JSON.toJSONString(jsonResult.getData());
        CourseInfoVo courseInfoVo = JSON.parseObject(jsonString, CourseInfoVo.class);
        // 所有下单课程
        List<Course> courses = courseInfoVo.getCourses();

        // 构建订单对象下单
        CourseOrder order = killOrder(loginId, preOrderDto);

//        insert(courseOrder);

        // 构建订单详情
        courses.forEach(course -> {
            CourseOrderItem item = createKillItem(preOrderDto, course);
            order.getItems().add(item);
//            itemService.insert(item);
        });

        // 封装发送到mq的消息
        PayMsgInMQ msgInMQ = new PayMsgInMQ();
        msgInMQ.setOrderNo(preOrderDto.getOrderNo());
        msgInMQ.setPayType(order.getPayType());// 支付宝
        msgInMQ.setAmount(order.getPayAmount());
        msgInMQ.setUserId(loginId);
        msgInMQ.setSubject(order.getTitle());

        Map<String, Object> map = new HashMap<>();
        map.put("userId", loginId);
        map.put("courseIds", ids);
        msgInMQ.setExtParams(JSON.toJSONString(map));
        // MQ发送事务消息
        Message<PayMsgInMQ> message = MessageBuilder.withPayload(msgInMQ).build();
        // order是额外参数
        TransactionSendResult result = mqTemplate.sendMessageInTransaction("tx-order-producer", "order-topic:order-tags", message, order);
        SendStatus sendStatus = result.getSendStatus();
        AssertUtil.isTrue(sendStatus.equals(SendStatus.SEND_OK), "支付订单创建失败");


        //添加定时任务【延时消息实现】
        Message<String> msg = MessageBuilder.withPayload(preOrderDto.getOrderNo()).build();
        SendResult res = mqTemplate.syncSend("killOrder-cancel-topic:killOrder-cancel-tags", msg, 3000, 4);//30s
        if (!res.getSendStatus().equals(SendStatus.SEND_OK)) {
            log.info("消息投递失败：{}", res);
        }
        // 删除redis token
        stringRedisTemplate.delete(RedisConstants.ORDER_TOKEN + loginId + ":" + ids);
        return preOrderDto.getOrderNo();
    }

    // 秒杀订单
    private CourseOrder killOrder(long loginId, PreOrderDTO preOrderDto) {
        CourseOrder courseOrder = new CourseOrder();
        courseOrder.setOrderNo(preOrderDto.getOrderNo());
        courseOrder.setOrderType(1);// 0 普通订单
        courseOrder.setCreateTime(new Date());
        // 支付方式:0余额直接，1支付宝，2微信,3银联
        courseOrder.setPayType(1);// 支付宝
        courseOrder.setTitle(YmccConstants.KILL_COURSE_ORDER);
        courseOrder.setStatusOrder(CourseOrder.TO_BE_PAID);//订单状态 0待支付
        courseOrder.setUserId(loginId);
        courseOrder.setDiscountAmount(new BigDecimal("0.00"));
        // 秒杀数量
        courseOrder.setTotalCount(1);
        courseOrder.setTotalAmount(preOrderDto.getKillPrice());
        courseOrder.setPayAmount(courseOrder.getTotalAmount().subtract(courseOrder.getDiscountAmount()));
        courseOrder.setVersion(0);
        return courseOrder;
    }
}
